#include "Timestamp.h"
#include <cstdio>
#include <inttypes.h>

namespace _zhy_muduo{

#if (defined(_MSC_VER))
int gettimeofday(struct timeval *tp, void *tzp)
{
	if (tzp) {
		//FIXME:
		printf("Windows ,gettimeofday not support timezone, only support UTC\n");
	}

    SYSTEMTIME wtm;
	GetSystemTime(&wtm);

    struct tm tm;
    tm.tm_year    = wtm.wYear - 1900;
    tm.tm_mon    = wtm.wMonth - 1;
    tm.tm_mday   = wtm.wDay;
    tm.tm_hour    = wtm.wHour;
    tm.tm_min     = wtm.wMinute;
    tm.tm_sec      = wtm.wSecond;
    tm. tm_isdst   = -1;

    tp->tv_sec = mktime(&tm);
    tp->tv_usec = wtm.wMilliseconds * 1000;
    return (0);
}
#endif

static_assert(sizeof(Timestamp) == sizeof(int64_t), "sizeof(Timestamp) == sizeof(int64_t)");

std::string Timestamp::toString() const
{
	char buf[32] = { 0 };
	int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
	int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
#if (defined(_MSC_VER))
	_snprintf(buf, sizeof(buf) - 1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
#elif (defined(__GNUC__))
#if (defined(PRId64))
	snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
#else
	snprintf(buf, sizeof(buf)-1, "%lld.%06lld", seconds, microseconds);
#endif
#else
	static_assert(false, "No instantiation, CHECK SYS!");
#endif
	return buf;
}

std::string Timestamp::toFormattedString(bool showMicroseconds) const
{
	char buf[32] = { 0 };
	time_t seconds = static_cast<time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
#if (defined(_MSC_VER))
	struct tm* tm_time = gmtime(&seconds);
	if (showMicroseconds && tm_time) {
	int microseconds = static_cast<int>(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);
		_snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d",
			 tm_time->tm_year + 1900, tm_time->tm_mon + 1, tm_time->tm_mday,
			 tm_time->tm_hour, tm_time->tm_min, tm_time->tm_sec,
			 microseconds);
	} else if (tm_time) {
		_snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d",
			 tm_time->tm_year + 1900, tm_time->tm_mon + 1, tm_time->tm_mday,
			 tm_time->tm_hour, tm_time->tm_min, tm_time->tm_sec);
	}
	return buf;
#elif (defined(__GNUC__))
	struct tm tm_time;
	gmtime_r(&seconds, &tm_time);
	if (showMicroseconds)
	{
		int microseconds = static_cast<int>(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);
		snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d",
			 tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
			 tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec,
			 microseconds);
	}
	else
	{
		snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d",
			 tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
			 tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
	}
	return buf;
#else
	static_assert(false, "No instantiation, CHECK SYS!");
#endif
}

Timestamp Timestamp::now()
{
	struct  timeval tv;
	gettimeofday(&tv, nullptr);
	int64_t seconds = tv.tv_sec;
	return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
}

#if 0
int64_t getCurrentMicroSeconds(void)
{
	struct timeval tv;
	gettimeofday(&tv , NULL);
	return tv.tv_sec * Timestamp::kMicroSecondsPerSecond + tv.tv_usec;
}
#endif
}// namespace _zhy_muduo